package net.caidingke.shepherd.security;

import lombok.AllArgsConstructor;
import net.caidingke.shepherd.security.handler.AjaxAuthenticationFailureHandler;
import net.caidingke.shepherd.security.handler.AjaxAuthenticationSuccessHandler;
import net.caidingke.shepherd.utils.constant.Const;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;
import net.caidingke.shepherd.security.handler.AjaxLogoutSuccessHandler;

import javax.annotation.PostConstruct;

/**
 * @author bowen
 */
@Configuration
@Import(SecurityProblemSupport.class)
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@AllArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    private final UserDetailsService userDetailsService;

    // private final RememberMeServices rememberMeServices;

    // private final SessionRegistry sessionRegistry;

    private final SecurityProblemSupport problemSupport;

    private final PasswordEncoder passwordEncoder;

    @PostConstruct
    public void init() {
        try {
            authenticationManagerBuilder
                    .userDetailsService(userDetailsService)
                    .passwordEncoder(passwordEncoder);
        } catch (Exception e) {
            throw new BeanInitializationException("Security configuration failed", e);
        }
    }

    @Bean
    public AjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandler() {
        return new AjaxAuthenticationSuccessHandler();
    }

    @Bean
    public AjaxAuthenticationFailureHandler ajaxAuthenticationFailureHandler() {
        return new AjaxAuthenticationFailureHandler();
    }

    @Bean
    public AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler() {
        return new AjaxLogoutSuccessHandler();
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers(HttpMethod.OPTIONS, "/**")
                .antMatchers("/app/**/*.{js,html}")
                .antMatchers("/i18n/**")
                .antMatchers("/content/**")
                .antMatchers("/swagger-ui/index.html")
                .antMatchers("/test/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.sessionManagement()
                // maximum number of concurrent sessions for one user
                .maximumSessions(32)
                //.sessionRegistry(sessionRegistry)
                .and()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(problemSupport)
                .accessDeniedHandler(problemSupport)
                .and()
                .rememberMe()
                .tokenValiditySeconds(60 * 60 * 24 * 180)
                .alwaysRemember(true)
                //.rememberMeServices(rememberMeServices)
                .rememberMeParameter(Const.COOKIE)
                .key(Const.KEY)
                .and()
                .formLogin()
                .loginProcessingUrl("/api/login")
                .successHandler(ajaxAuthenticationSuccessHandler())
                .failureHandler(ajaxAuthenticationFailureHandler())
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/api/logout")
                .logoutSuccessHandler(ajaxLogoutSuccessHandler())
                .deleteCookies(Const.COOKIE)
                .permitAll()
                .and()
                .headers()
                .frameOptions()
                .disable()
                .and()
                .authorizeRequests()
                .antMatchers("/api/register").permitAll()
                .antMatchers("/api/login").permitAll()
                .antMatchers("/api/test").permitAll()
                //.antMatchers("/api/**").authenticated()
                .antMatchers("/api/**").permitAll()
                .antMatchers("/env").permitAll()
                .antMatchers("/management/metrics").hasAnyAuthority(Const.ADMIN)
                //.antMatchers("/swagger-ui.html").hasAuthority(Const.ADMIN);
                .antMatchers("/swagger-ui.html").permitAll();
        http.csrf().disable();
    }

}
